#define NOMINMAX
#include "CreditDebtRankingData.h"
#include "../FIDataCenter.h"
#include <bondlib/BondInfo.h>
#include <bondlib/BondContainer.h>
#include <bondlib/BondDeal/PanoramicBondDealContainer.h>
#include <bondlib/BondDeal/PanoramicBondDealStruct.h>
#include <qbkernel/include/qb_base.h>
#include <datareceiver/PanoramicDealReceiver.h>
#include <map>
#include <uam/UserAccountManager.h>

CNewBondPanDeal::CNewBondPanDeal()
{
	Initial();
}

void CNewBondPanDeal::Initial()
{
	m_nCount = 0; 
	m_dbHigh = 0.0f;
	m_dbLow = 0.0f;
	m_dbAdv = 0.0f;
	m_nYeildNumb = m_nCleanNumb = 0;
	m_bCleanCal = true;
}

bool CNewBondPanDeal::addDeal(const sPanoramicBondDealUnit& unitD)
{
	if (unitD.m_updateTime > m_updateTime ||
		((unitD.m_updateTime == m_updateTime) && (unitD.m_indexID > m_indexID))) {
		*this = unitD;
	}
	dealCalculator(unitD);
	m_nCount++;
	return true;
}

bool CNewBondPanDeal::dealCalculator(const sPanoramicBondDealUnit& unitD)
{
	bool bClean = unitD.IsCleanPrice() || unitD.IsFullPrice();
	double dbPrc = atof(unitD.m_price);
	if (bClean) {
		m_nCleanNumb++;
		if (m_nCleanNumb < 1) return false;
		if (m_bCleanCal) {
			if (m_nCleanNumb == 1) m_dbHigh = m_dbLow = m_dbAdv = dbPrc;
			else {
				m_dbHigh = std::max(m_dbHigh, dbPrc);
				m_dbLow = std::min(m_dbLow, dbPrc);
				m_dbAdv = (m_dbAdv * (m_nCleanNumb - 1) + dbPrc) / m_nCleanNumb;
			}
		}
	}
	else {
		m_nYeildNumb++;
		if (m_nYeildNumb < 1) return false;
		if (m_bCleanCal) {
			m_bCleanCal = false;
			m_dbHigh = m_dbLow = m_dbAdv = atof(unitD.m_price);
		}
		else {
			if (m_nYeildNumb == 1) m_dbHigh = m_dbLow = m_dbAdv = dbPrc;
			else {
				m_dbHigh = std::max(m_dbHigh, dbPrc);
				m_dbLow = std::min(m_dbLow, dbPrc);
				m_dbAdv = (m_dbAdv * (m_nYeildNumb - 1) + dbPrc) / m_nYeildNumb;
			}
		}
	}
	return true;
}

bool CNewBondPanDeal::removeDeal(const sPanoramicBondDealUnit& unitD)
{
	return true;
}

constexpr double COMPARE_DOUBLE = 0.0001;

CreditDebtRankingData::CreditDebtRankingData()
{
	for (int i= CreditDebtRankingData::prod_Intel; i<CreditDebtRankingData::prod_Max; i++){
		m_filter.push_back(i); //默认设置全部产品
	}

	connect(&PanoramicDealReceiver::instance(), &PanoramicDealReceiver::dealMarketPush, this, &CreditDebtRankingData::onDealPush);
	connect(&PanoramicDealReceiver::instance(), &PanoramicDealReceiver::dealMarketArrived, this, &CreditDebtRankingData::onDataArrived);
}

void CreditDebtRankingData::onDealPush(int32_t, QList<xQBPanoramicMarketStreamUnit> lstData)
{
	if (!lstData.isEmpty())
	{
		loadData();
		m_lstFlash.clear();
		for (const auto& data : lstData)
			m_lstFlash.emplace_back(data.m_bondCode);

		emit newDataArrived();
	}
}

void CreditDebtRankingData::onDataArrived()
{
	bool bNewDealSource = strcmp(SSUserAccountManager::instance().GetGlobleVariabl(SSUserAccountManager::UseNewDealSource), "1") == 0;
	if (bNewDealSource)return;
	loadData();
	m_lstFlash.clear();
	emit newDataArrived();	
}

void CreditDebtRankingData::loadData()
{
#define _insert_deal(type, bCredit)\
{\
	auto& deal = dealMap.getBondDeal(type);\
	for (auto iter : deal)\
	{\
		if (iter.second.m_count <= 0)continue;\
		int bondIndex = iter.first;\
		if (!bc.IsValidIndex(bondIndex))continue;\
		const CBondInfo& bi = bc.ElementAtR(bondIndex);\
		QString tmp = QString::fromLocal8Bit(bi.GetCombBondKey());\
		CNewBondPanDeal& panDeal = m_mapRank[tmp];\
		if(bCredit)m_setCreditBond.insert(tmp);\
		for (auto itDeal : iter.second.m_tradeList)\
		{\
			if (atoi(itDeal.m_dealStatus) >= 4)continue;\
			if (strcmp(itDeal.m_withinPeriodDeal, "N") == 0) {\
				setFirst.insert(tmp);\
			}\
			panDeal.addDeal(itDeal);\
		}\
	}\
}
	clearData();
	std::set<QString> setFirst;
	{
		CBondContainer& bc = CBondContainer::instance();
		SCOPED_LOCK(CPanoramicBondDealContainer::instance().GetLock());
		CPanoramicBondDealMap& dealMap = CPanoramicBondDealContainer::instance().GetDealMap();

		_insert_deal(panoramic::bondType_interest, false);
		//_insert_deal(panoramic::bondType_credit, true);
		{
			auto& deal = dealMap.getBondDeal(panoramic::bondType_credit);
			for (auto& iter : deal)
			{
				if (iter.second.m_count <= 0)continue;
				int bondIndex = iter.first;
				if (!bc.IsValidIndex(bondIndex))continue;
				const CBondInfo& bi = bc.ElementAtR(bondIndex);
				QString tmp = QString::fromLocal8Bit(bi.GetCombBondKey());
				CNewBondPanDeal& panDeal = m_mapRank[tmp];
				if (true)m_setCreditBond.insert(tmp);
				for (auto itDeal : iter.second.m_tradeList)
				{
					if (atoi(itDeal.m_dealStatus) >= 4)continue;
					if (strcmp(itDeal.m_withinPeriodDeal, "N") == 0) {

						setFirst.insert(tmp);
					}
					panDeal.addDeal(itDeal);
				}
			}
		}
		_insert_deal(panoramic::bondType_ncd, false);
	}

	for (auto itrSet=setFirst.begin(); itrSet!=setFirst.end(); ++itrSet) {
		m_lstFirstDeal.push_back(*itrSet);
	}
	sortListData();
}

void CreditDebtRankingData::clearData()
{
	m_mapRank.clear();
	m_lstRankUpDown.clear();
	m_lstRankDeviate.clear();
	m_lstFirstDeal.clear();
	m_setCreditBond.clear();
}

void CreditDebtRankingData::sortListData()
{
	double dbCurUp, dbCurDeviate, dbComp, dbCDCGapClearPrice;
	for (auto itr = m_setCreditBond.begin(); itr != m_setCreditBond.end(); itr++) {
		const CNewBondPanDeal& pDeal = m_mapRank[*itr];
		dbCurUp = pDeal.m_closeGapPercent;
		dbCurDeviate = pDeal.m_cdcGapPercent;
		dbCDCGapClearPrice = fabs(pDeal.m_cdcGapCleanPrice);
		if (dbCDCGapClearPrice < 4.999) {//剔除剩余期限小于 0.5 年且净价变动绝对值小于 0.05 元的债券，非永续债
			CBondContainer& bc = CBondContainer::instance();
			int bondIndex = bc.GetBondIndex(pDeal.m_bondkey, pDeal.m_listedmarket);
			if (!bc.IsValidIndex(bondIndex)) continue;
			const CBondInfo& bi = bc.ElementAtR(bondIndex);
			if (bi.IsRatingDebt()) continue;
			if (!bi.IsETSBond()) {
				float fRamainYear = bi.GetRemainYear(pDeal.m_updateTime);
				if (fRamainYear < 0.5) continue;
			}
		}

		std::list<QString>::const_iterator itrUpDown = m_lstRankUpDown.begin();
		std::list<QString>::const_iterator itrDeviate = m_lstRankDeviate.begin();
		for (; itrDeviate != m_lstRankDeviate.end(); itrDeviate++) {
			dbComp = m_mapRank[*itrDeviate].m_cdcGapPercent;
			if (dbCurDeviate > dbComp) break;
		}
		if (itrDeviate == m_lstRankDeviate.end()) m_lstRankDeviate.push_back(*itr);
		else m_lstRankDeviate.insert(itrDeviate, *itr);
	}
}

void CreditDebtRankingData::setFilter(const std::vector<int>& filter, int fltProd)
{
	m_filter = filter;
	m_nFirstType = fltProd;
}

void CreditDebtRankingData::getFilter(std::vector<int>& filter)
{
	filter = m_filter;
}

bool CreditDebtRankingData::verifyFirstFilter(const CNewBondPanDeal& panD, bool bList/*是否上市日*/)
{
	int FilterCount = 0;

	if (bList && strcmp(panD.m_listedFirstDeal, "N") != 0) return false;
	int nSz = (int)m_filter.size();
	if (nSz == 0) return false;

	CBondContainer& bc = CBondContainer::instance();
	int bondIndex = bc.GetBondIndex(panD.m_bondkey, panD.m_listedmarket);
	if (!bc.IsValidIndex(bondIndex))return false;
	const CBondInfo& bondInfo = bc.ElementAtR(bondIndex);
	for (int nL = 0; nL < nSz; nL++) {
		switch (m_filter[nL]) {
		case prod_All: {
			return true;
		}
		case prod_Intel: {
			if (bondInfo.IsRatingDebt()) FilterCount++;
			continue;
		}
		case prod_Short: {
			if (bondInfo.CheckBondTypeNew(CBondContainer::newBondShort)) FilterCount++;
			continue;
		}
		case prod_ZP: {
			if (bondInfo.CheckBondTypeNew(CBondContainer::newBondMTN)) FilterCount++;
			continue;
		}
		case prod_Ent: {
			if (bondInfo.CheckBondTypeNew(CBondContainer::newBondEnterpr)) FilterCount++;
			continue;
		}
		case prod_Comp: {
			if (bondInfo.CheckBondTypeNew(CBondContainer::newBondCOP)) FilterCount++;
			continue;
		}
		case prod_PPN: {
			if (bondInfo.CheckBondTypeNew(CBondContainer::newBondPPN)) FilterCount++;
			continue;
		}
		case prod_NCD: {
			if (bondInfo.CheckBondTypeNew(CBondContainer::newBondNCD)) FilterCount++;
			continue;
		}
		case prod_Other: {
			if (bondInfo.CheckBondTypeNew(CBondContainer::newBondABS) ||
				bondInfo.CheckBondTypeNew(CBondContainer::newBondCRM) ||
				bondInfo.CheckBondTypeNew(CBondContainer::newBondOther)) FilterCount++;
			continue;
		}
		default:
			continue;
		}
	}

	if (FilterCount > 0){
		return true;
	}
	return false;
}

bool CreditDebtRankingData::verifyUpDown(const CNewBondPanDeal& panD, bool bCDC)
{
	if (panD.m_Redemption_No != 0) return false; //提前还本
	float fCln = atof(panD.m_cleanPrice);
	if (fCln > -COMPARE_DOUBLE && fCln < COMPARE_DOUBLE) {
		return false;
	}
	if (bCDC) {
		if ((panD.m_cdcGapPercent > COMPARE_DOUBLE && panD.m_cdcGapBP > COMPARE_DOUBLE) ||
			(panD.m_cdcGapPercent < -COMPARE_DOUBLE && panD.m_cdcGapBP < -COMPARE_DOUBLE)) {
			return false;
		}
	}
	else {
		if ((panD.m_closeGapPercent > COMPARE_DOUBLE && panD.m_closeGapBP > COMPARE_DOUBLE) ||
			(panD.m_closeGapPercent < -COMPARE_DOUBLE && panD.m_closeGapBP < -COMPARE_DOUBLE)) {
			return false;
		}
	}

	CBondContainer& bc = CBondContainer::instance();
	int bondIndex = bc.GetBondIndex(panD.m_bondkey, panD.m_listedmarket);
	if (!bc.IsValidIndex(bondIndex)) return false;
	const CBondInfo& bondInfo = bc.ElementAtR(bondIndex);
	if (strcmp(bondInfo.GetOptionType(), "ETS") == 0) {
		return false;
	}
	return true;
}

bool CreditDebtRankingData::getTopDealData(std::vector<CNewBondPanDeal>& lstDeal, int bondType, int cunt /*= 20 /*前后数目*/, bool bNeedCount)
{
	std::list<QString>::const_iterator itrBd;
	std::list<QString>::const_reverse_iterator itrBdRev;
	switch (bondType){
	case type_RankUp:{//按涨跌前20
		for (itrBd = m_lstRankUpDown.begin(); itrBd != m_lstRankUpDown.end() && cunt > 0; itrBd++) {
			const CNewBondPanDeal& panDeal = m_mapRank[*itrBd];
			if (panDeal.m_closeGapPercent < COMPARE_DOUBLE) break;
			if (!verifyUpDown(panDeal, false)) continue;
			lstDeal.push_back(panDeal);
			if (bNeedCount) cunt--;
		}
		break;
	}
	case type_RankDown:{//按涨跌后20
		for (itrBdRev = m_lstRankUpDown.rbegin(); itrBdRev != m_lstRankUpDown.rend() && cunt > 0; itrBdRev++) {
			const CNewBondPanDeal& panDeal = m_mapRank[*itrBdRev];
			if (panDeal.m_closeGapPercent > -COMPARE_DOUBLE) break;
			if (!verifyUpDown(panDeal, false)) continue;
			lstDeal.push_back(panDeal);
			if (bNeedCount) cunt--;
		}
		break;
	}
	case type_DeviateUp:{//按偏离值前20
		for (itrBd = m_lstRankDeviate.begin(); itrBd != m_lstRankDeviate.end() && cunt > 0; itrBd++) {
			const CNewBondPanDeal& panDeal = m_mapRank[*itrBd];
			if (panDeal.m_cdcGapPercent < COMPARE_DOUBLE) break;
			if (!verifyUpDown(panDeal, true)) continue;
			lstDeal.push_back(panDeal);
			if (bNeedCount) cunt--;
		}
		break;
	}
	case type_DeviateDown:{//按偏离值后20
		for (itrBdRev = m_lstRankDeviate.rbegin(); itrBdRev != m_lstRankDeviate.rend() && cunt > 0; itrBdRev++) {
			const CNewBondPanDeal& panDeal = m_mapRank[*itrBdRev];
			if (panDeal.m_cdcGapPercent > -COMPARE_DOUBLE) break;
			if (!verifyUpDown(panDeal, true)) continue;
			lstDeal.push_back(panDeal);
			if (bNeedCount) cunt--;
		}
		break;
	}
	case type_FirstDeal:{//首次成交
		for (itrBd = m_lstFirstDeal.begin(); itrBd != m_lstFirstDeal.end(); itrBd++) {
			const CNewBondPanDeal& panDeal = m_mapRank[*itrBd];
			if (verifyFirstFilter(panDeal, m_nFirstType != fst_Tab_20))	lstDeal.push_back(m_mapRank[*itrBd]);
		}
		break;
	}
	case type_Active:{//活跃成交
		std::set<QString> setLoop;
		QString strCur;
		while (cunt > 0) {
			int nMaxNumb = 0;
			strCur = "";
			for (auto itr = m_setCreditBond.begin(); itr != m_setCreditBond.end(); itr++) {
				if (setLoop.find(*itr) != setLoop.end()) continue;
				const CNewBondPanDeal& panDeal = m_mapRank[*itr];
				if (panDeal.m_nCount > nMaxNumb) {
					nMaxNumb = panDeal.m_nCount;
					strCur = *itr;
				}
			}
			if (nMaxNumb <= 0 || strCur.isEmpty()) break;
			lstDeal.push_back(m_mapRank[strCur]);
			setLoop.insert(strCur);
			cunt--;
		}
		break;
	}
	default:
		break;
	}
	return true;
}

const std::list<std::string>& CreditDebtRankingData::getFlash() const
{
	return m_lstFlash;
}